package com.lsp.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lsp.constant.EsConstant;
import com.lsp.feign.ProductFeign;
import com.lsp.mapper.*;
import com.lsp.service.MallServeice;
import com.lsp.vo.AttrResponseVo;
import com.lsp.vo.SearchParam;
import com.lsp.vo.SearchResult;
import com.lsp.vo.SkuEsModel;
import com.shop.pojo.pms.*;
import com.shop.to.AttrTo;
import com.shop.utils.R;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.swing.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@Service
public class MallServiceImpl implements MallServeice {
    @Autowired
    private RestHighLevelClient client;
@Autowired
    private RestHighLevelClient restHighLevelClient;
@Autowired
private BrandService brandService;
@Autowired
private ProductFeign productFeign;
@Autowired
private SkuInfoMapper skuInfoMapper;
    @Autowired
    private Pms_Attr_Value_Mapper pms_attr_value_mapper;
    @Autowired
    private AttrMapper attrMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private BrandMapper brandMapper;

    public Object search(SearchParam searchParam) {


        //1.动态构建出查询需要的dsl语句
        SearchResult result=null;
        SearchRequest searchRequest=buildSearchRequest(searchParam);
        //解析前台传来的一些属性




        try {
            //执行检索请求
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//System.out.println(search.toString());
                //  System.out.println(  search.status()+"端口");
            //分析响应数据封装成我们需要的格式
          result=buildSearchRequest(search,searchParam);
        } catch (IOException e) {
            e.printStackTrace();
        }


        return result;
    }

    @Override
    public R skuPutaway(Long spuId) {
        List<SkuEsModel> skuEsModels = new ArrayList<SkuEsModel>();

        //1、查询出当前spuId对应的所有sku信息,包含了品牌的名字
        List<Pms_Sku_Info> skus = skuInfoMapper.selectList(new QueryWrapper<Pms_Sku_Info>().eq("spu_id", spuId));
        //TOOD 4、查询当前sku的所有可以来被检索的规格属性id和值
        List<Pms_Product_Attr_Value> pms_attrs = pms_attr_value_mapper.selectListAllAttr(skus.get(0).getSku_id());
        //获取到全部的attrId
        List<Long> searchAttrId = pms_attrs.stream().map(skuattr -> {
            return skuattr.getAttr_id();
        }).collect(Collectors.toList());
        //
        Set<Long> idSet = new HashSet<>(searchAttrId);

        //给attrs赋值
        List<SkuEsModel.Attrs> attrsList = pms_attrs.stream().map(item -> {
            SkuEsModel.Attrs attrs1 = new SkuEsModel.Attrs();
            item.getAttr_id();
            Pms_Attr attr_name = attrMapper.selectOne(new QueryWrapper<Pms_Attr>().eq("attr_id", item.getAttr_id()));
            attrs1.setAttrId(item.getAttr_id());
            attrs1.setAttrValue(item.getAttr_value());
            attrs1.setAttrName(attr_name.getAttr_name());
            return attrs1;
        }).collect(Collectors.toList());
        System.out.println("我要开始了");


        List<SkuEsModel> collect_skuEs = skus.stream().map(sku -> {
            //组装需要的数据
            SkuEsModel sm = new SkuEsModel();
            BeanUtils.copyProperties(sku, sm);
            sm.setSkuId(sku.getSku_id());
            sm.setSpuId(sku.getSpu_id());
            sm.setSkuPrice(sku.getPrice());
            sm.setSkuTitle(sku.getSku_title());
            sm.setSkuImg(sku.getSku_default_img());
            sm.setSaleCount(sku.getSale_count());
            sm.setBrandId(sku.getBrand_id());
            sm.setCatalogId(sku.getCatalog_id());
            //TOOD 1、发送远程调用,库存系统是否有库存
            sm.setHasStock(true);
            //TOOD 2、热度评分
            sm.setHotstock(0L);
            //TOOD 3、查询品牌和分类的名字的信息
            String cat_name = categoryMapper.selectOne(new QueryWrapper<Pms_Category>().eq("cat_id", sku.getCatalog_id())).getName();//分类
            Pms_Brand brand = brandMapper.selectOne(new QueryWrapper<Pms_Brand>().eq("brand_id", sku.getBrand_id()));//品牌
            sm.setCatalogName(cat_name);
            sm.setBrandName(brand.getName());
            sm.setBrandImg(brand.getLogo());
            attrsList.forEach(System.out::println);
            sm.setAttrs(attrsList);
            return sm;
        }).collect(Collectors.toList());
        //保存到es
        //1.创建索引
        //2.添加内容


        try {
            BulkRequest bulkRequest = new BulkRequest();
            for (SkuEsModel model : collect_skuEs) {
                //1.构造保存请求
                IndexRequest indexRequest = new IndexRequest("product");
                indexRequest.id(model.getSkuId().toString());
                String s = JSON.toJSONString(model);
                indexRequest.source(s, XContentType.JSON);
                bulkRequest.add(indexRequest);
            }
            BulkResponse  bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
         //   boolean b = bulk.hasFailures();
            return R.ok();
        } catch (IOException e) {
            e.printStackTrace();
            return R.error(505,"当前不可删除");
        }


    }

    @Override
    public R skuSoldOut(Long spuId) {

        try {
            List<Pms_Sku_Info> skus = skuInfoMapper.selectList(new QueryWrapper<Pms_Sku_Info>().eq("spu_id", spuId));
            for (Pms_Sku_Info pms_sku_info : skus) {
                DeleteRequest deleteRequest=new DeleteRequest("product");
                DeleteRequest id = deleteRequest.id(String.valueOf(pms_sku_info.getSku_id()));
                DeleteResponse delete = client.delete(id, RequestOptions.DEFAULT);
            }

            return R.ok();
        } catch (IOException e) {
            e.printStackTrace();
            return R.error(505,"当前不可删除");
        }

    }

    //2/准备检索请求
    /*
     * @Description
     * @param 模糊匹配。过滤（按照属性，分类，品牌，价格区间，库存），排序，分页，高亮，聚合分析
     * @return org.elasticsearch.action.search.SearchRequest
     * @author liusupeng
     * @date 2020/10/19 18:06
     */
    private SearchRequest buildSearchRequest(SearchParam searchParam) {

        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();

        /**
         * 查询模糊匹配。过滤（按照属性，分类，品牌，价格区间，库存）
         * */
        //1.构建了bool -query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //1-1must的模糊匹配
        if(!StringUtils.isEmpty(searchParam.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword()));
        }
        //1-2 bool- filter -按照三级分类id查询
        if(searchParam.getCatalog3Id()!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id()));
        }
        //1-2 bool- filter -按照品牌的id查询
        if(searchParam.getBrandId()!=null&&searchParam.getBrandId().size()>0){
            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
        }
        //1-2 bool- filter -按照所有指定的属性查询
          if(searchParam.getAttrs()!=null && searchParam.getAttrs().size()>0){

              for (String attrStr:searchParam.getAttrs()) {
                  System.out.println(attrStr);
                  //&attrs=2_5寸：2寸&attrs=2_16G:8G
                  BoolQueryBuilder nestBoolQuery = QueryBuilders.boolQuery();
                  //attr=1_5寸：8寸
               String[] s = attrStr.split("_");
               String attrId=s[0];//属性ID
                  String[] attrValues=s[1].split(":");//检索的属性值
             System.out.println("我是id"+attrId);
             System.out.println("我是value"+attrValues);

                nestBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",attrId));
                  nestBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue.keyword",attrValues));
                  //每一个都必须要生成一个nested查询
                  NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs", nestBoolQuery, ScoreMode.None);
                  boolQueryBuilder.filter(nestedQuery);
              }

             // boolQueryBuilder.must(nestedQuery);

          }
        //1-2 bool- filter -按照是否拥有库存
        if(searchParam.getHasStock()!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("hasStock",searchParam.getHasStock()==1));
        }

        //1-2 bool- filter -价格区间
        if(!StringUtils.isEmpty(searchParam.getSkuPrice())){
            //1_500/_500/500_
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");
            String split[]=searchParam.getSkuPrice().split("_");
            if(split.length==2){
                rangeQuery.gte(split[0]).lte(split[1]);

            }else if(split.length==1){
                //以_开头的
                if(searchParam.getSkuPrice().startsWith("_")){
                    rangeQuery.lte(split[0]);
                }
                //以_结尾的
                if(searchParam.getSkuPrice().endsWith("_")){
                    rangeQuery.gte(split[0]);
                }
            }
            boolQueryBuilder.filter(rangeQuery);
        }
        //拿到以前所有的条件拿来继续封装
        searchSourceBuilder.query(boolQueryBuilder);


        /**
         *排序，分页，高亮，聚合分析
         */
        //排序
         if(!StringUtils.isEmpty(searchParam.getSort())){
             String sort=searchParam.getSort();
             String[] s=sort.split("_");
             SortOrder order = s[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC;
           //  System.out.println("我是字符："+s[0]+"我排序"+order.toString());
             searchSourceBuilder.sort(s[0],order);

         }
         //分页
        if(searchParam.getPage()!=null){
            System.out.println("我不为空");
            searchSourceBuilder.from((searchParam.getPage()-1)* EsConstant.PRODUCT_PAGESIZE);
            searchSourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);
        }


        //高亮
        if(!StringUtils.isEmpty(searchParam.getKeyword())){

            HighlightBuilder builder=new HighlightBuilder();
            builder.field("skuTitle");
            builder.preTags("<b style='color:red'>");

            builder.postTags("</b>");
            searchSourceBuilder.highlighter(builder);
        }



        /**
         * 聚合分析
         * */
        //品牌聚合
        TermsAggregationBuilder brand_agg = AggregationBuilders.terms("brand_agg").field("brandId").size(50);//聚合的字段名和多少个数量;
        //品牌聚合的子聚合
        brand_agg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName.keyword").size(1));
        brand_agg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg.keyword").size(1));
        searchSourceBuilder.aggregation(brand_agg);
        //分类聚合
        TermsAggregationBuilder catalogCatalog = AggregationBuilders.terms("catalog_agg").field("catalogId").size(20);
        catalogCatalog.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName.keyword").size(1));
        searchSourceBuilder.aggregation(catalogCatalog);
        //属性聚合
        NestedAggregationBuilder attr_agg = AggregationBuilders.nested("attr_agg", "attrs");
        TermsAggregationBuilder attr_id_agg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");
        //聚合分析出当前id对应的名字
        attr_id_agg.subAggregation(AggregationBuilders.terms("attr_Name_agg").field("attrs.attrName.keyword").size(1));
        attr_id_agg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue.keyword").size(50));
        attr_agg.subAggregation(attr_id_agg);
        searchSourceBuilder.aggregation(attr_agg);


        SearchRequest searchRequest = new SearchRequest("product");
        searchRequest.source(searchSourceBuilder);
        String s = searchRequest.toString();
     System.out.println("构建的DSL" + s);
        return searchRequest;
    }
    //构建结果数据
    /*
     * @Description
     * @param
     * @return org.elasticsearch.action.search.SearchRequest
     * @author liusupeng
     * @date 2020/10/19 18:06
     */
    private SearchResult buildSearchRequest(SearchResponse response,SearchParam param) {

        SearchResult result=new SearchResult();
        //1/返回所有查询到的商品
        SearchHits hits=response.getHits();
        List<SkuEsModel> esModels=new ArrayList<>();
        if(hits.getHits()!=null && hits.getHits().length>0){
            for(SearchHit hit:hits.getHits()){
          //     System.out.println("hits:"+hit.toString());
                String sourceAsString=hit.getSourceAsString();
            //    System.out.println("hit:"+sourceAsString);
                SkuEsModel esModel= JSON.parseObject(sourceAsString,SkuEsModel.class);
           //     System.out.println("esmodel:"+esModel);
                //高亮显示
                if(!StringUtils.isEmpty(param.getKeyword())){
                    HighlightField skuTitleHighlightField = hit.getHighlightFields().get("skuTitle");
                    String string = skuTitleHighlightField.getFragments()[0].string();
                    esModel.setSkuTitle(string);
                }
                esModels.add(esModel);
            }
        }
        result.setProducts(esModels);
        //2.当前所有商品设计到的所有属性信息
        List<SearchResult.AttrVo> attrVos=new ArrayList<>();
        ParsedNested attr_agg = response.getAggregations().get("attr_agg");
        ParsedLongTerms attr_id_agg = attr_agg.getAggregations().get("attr_id_agg");
        for(Terms.Bucket bucket:attr_id_agg.getBuckets()){
            SearchResult.AttrVo attrVo=new SearchResult.AttrVo();
            //1、得到属性的id
            long attrId = bucket.getKeyAsNumber().longValue();
            //得到属性的名字
            String attrName=((ParsedStringTerms)bucket.getAggregations().get("attr_Name_agg")).getBuckets().get(0).getKeyAsString();
            //得到属性的所有值
            List<String> attr_value_agg = ((ParsedStringTerms) bucket.getAggregations().get("attr_value_agg")).getBuckets().stream().map(item -> {
                String keyAsString = ((Terms.Bucket) item).getKeyAsString();
                return keyAsString;
            }).collect(Collectors.toList());
            attrVo.setAttrId(attrId);
            attrVo.setAttrName(attrName);
            attrVo.setAttrValue(attr_value_agg);
attrVos.add(attrVo);
        }
      result.setAttrs(attrVos);
          //当前商品设计到的所有品牌信息
        List<SearchResult.BrandVo> brandVos=new ArrayList<>();
        ParsedLongTerms brand_agg = response.getAggregations().get("brand_agg");
        for(Terms.Bucket bucket:brand_agg.getBuckets()){
            SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
            //得到品牌的id
            Long brandId=bucket.getKeyAsNumber().longValue();
            //得到品牌的名字
            String brandName=((ParsedStringTerms)bucket.getAggregations().get("brand_name_agg")).getBuckets().get(0).getKeyAsString();
            //得到品牌的图片
           String brandImg=((ParsedStringTerms)bucket.getAggregations().get("brand_img_agg")).getBuckets().get(0).getKeyAsString();
            brandVo.setBrandId(brandId);
           brandVo.setBrandImg(brandImg);
            brandVo.setBrandName(brandName);
            brandVos.add(brandVo);
        }
        result.setBrands(brandVos);
        //分类
        ParsedLongTerms catalog_agg = response.getAggregations().get("catalog_agg");
        List<SearchResult.CatalogVo> catalogVos = new ArrayList<>();
        List<? extends Terms.Bucket> buckets = catalog_agg.getBuckets();
        for (Terms.Bucket bucket : buckets) {
            SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();

            String keyAsString = bucket.getKeyAsString();

            catalogVo.setCatalogId(Long.parseLong(keyAsString));

            // 获取分类名子聚合 catalog_name_agg
            ParsedStringTerms catalog_name_agg = bucket.getAggregations().get("catalog_name_agg");
            String catalog_name = catalog_name_agg.getBuckets().get(0).getKeyAsString();
            catalogVo.setCatalogName(catalog_name);

            catalogVos.add(catalogVo);
        }
        result.setCatalogs(catalogVos);
        //分页信息
        result.setPageNum(param.getPage());
        //分页总记录数
          long total=  hits.getTotalHits().value;
          result.setTotal(total);
        int totalPages = (int) total % EsConstant.PRODUCT_PAGESIZE == 0 ? (int) total / EsConstant.PRODUCT_PAGESIZE : ((int) total / EsConstant.PRODUCT_PAGESIZE + 1);
        result.setTotalPages(totalPages);
        //构建面包屑
        if(param.getAttrs()!=null&&param.getAttrs().size()>0){
            System.out.println("我的数量:"+param.getAttrs().size());
            List<SearchResult.NavVo> collect = param.getAttrs().stream().map((item) -> {
                SearchResult.NavVo navVo = new SearchResult.NavVo();
                String[] s = item.split("_");
                Long attrId = Long.parseLong(s[0]);
                String values = s[1].replace(":", "、");//属性值
                AttrTo nameByAttrId = productFeign.findNameByAttrId(attrId);
                if(nameByAttrId.getCode()==200){
                    navVo.setNavName(nameByAttrId.getAttrName());
                }else{
                    navVo.setNavName(String.valueOf(attrId));
                }
                navVo.setNavValue(values);
                navVo.setLink(item);
                return navVo;
            }).collect(Collectors.toList());
            if(collect!=null){
                result.setNavs(collect);
            }
        }


        // 构建遍历需要的页码
        List<Integer> pageNavs = new ArrayList<>();
        for (int i = 1; i <= totalPages; i++) {
            pageNavs.add(i);
        }
        result.setPageNavs(pageNavs);



        return result;

    }
}
